package org.chartsy.mfi;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.text.DecimalFormat;
import java.util.LinkedHashMap;
import org.chartsy.main.ChartFrame;
import org.chartsy.main.chart.Indicator;
import org.chartsy.main.data.DataItem;
import org.chartsy.main.data.Dataset;
import org.chartsy.main.utils.DefaultPainter;
import org.chartsy.main.utils.Range;
import org.chartsy.main.utils.SerialVersion;
import org.chartsy.main.utils.StrokeGenerator;
import org.openide.nodes.AbstractNode;
/**
*
* @author viorel.gheba
*/
public class MoneyFlowIndex
extends Indicator
{
private static final long serialVersionUID = SerialVersion.APPVERSION;
public static final String MFI = "mfi";
private IndicatorProperties properties;
public MoneyFlowIndex()
{
super();
properties = new IndicatorProperties();
}
public String getName(){ return "MFI"; }
public String getLabel()
{ return properties.getLabel() + " (" + properties.getPeriod() + ")"; }
public String getPaintedLabel(ChartFrame cf){ return getLabel(); }
public Indicator newInstance(){ return new MoneyFlowIndex(); }
public LinkedHashMap getHTML(ChartFrame cf, int i)
{
LinkedHashMap ht = new LinkedHashMap();
DecimalFormat df = new DecimalFormat("#,##0.00");
double[] values = getValues(cf, i);
String[] labels = {"MFI:"};
ht.put(getLabel(), " ");
if (values.length > 0) {
Color[] colors = getColors();
for (int j = 0; j < values.length; j++) {
ht.put(getFontHTML(colors[j], labels[j]),
getFontHTML(colors[j], df.format(values[j])));
}
}
return ht;
}
@Override
public Range getRange(ChartFrame cf){ return new Range(0, 100); }
public void paint(Graphics2D g, ChartFrame cf, Rectangle bounds)
{
Dataset d = visibleDataset(cf, MFI);
if (d != null)
{
if (maximized)
{
Range range = getRange(cf);
DefaultPainter.line(g, cf, range, bounds, d, properties.getColor(), properties.getStroke()); // paint line
if (properties.getInsideVisibility())
{
paintFill(g, cf, d, bounds, range, properties.getInsideTransparentColor(), 20d, 0d, false);
paintFill(g, cf, d, bounds, range, properties.getInsideTransparentColor(), 80d, 100d, true);
}
}
}
}
public void calculate()
{
Dataset initial = getDataset();
if (initial != null && !initial.isEmpty())
{
int period = properties.getPeriod();
Dataset d = getDataset(initial, period);
addDataset(MFI, d);
}
}
public boolean hasZeroLine(){ return false; }
public boolean getZeroLineVisibility(){ return false; }
public Color getZeroLineColor(){ return null; }
public Stroke getZeroLineStroke(){ return null; }
public boolean hasDelimiters(){ return true; }
public boolean getDelimitersVisibility(){ return true; }
public double[] getDelimitersValues(){ return new double[] {20d, 50d, 80d}; }
public Color getDelimitersColor(){ return properties.getDelimiterColor(); }
public Stroke getDelimitersStroke(){ return properties.getDelimiterLineStroke(); }
public Color[] getColors(){ return new Color[] {properties.getColor()}; }
public boolean getMarkerVisibility(){ return properties.getMarker(); }
public AbstractNode getNode(){ return new IndicatorNode(properties); }
public double[] getValues(ChartFrame cf)
{
Dataset d = visibleDataset(cf, MFI);
if (d != null)
return new double[] {d.getLastClose()};
return new double[] {};
}
public double[] getValues(ChartFrame cf, int i)
{
Dataset d = visibleDataset(cf, MFI);
if (d != null)
return new double[] {d.getCloseAt(i)};
return new double[] {};
}
@Override
public Double[] getPriceValues(ChartFrame cf)
{ return new Double[] {new Double(20), new Double(50), new Double(80)}; }
private Dataset getDataset(final Dataset initial, final int period)
{
int count = initial.getItemsCount();
Dataset posMF = Dataset.EMPTY(count);
Dataset negMF = Dataset.EMPTY(count);
for (int i = 1; i < count; i++)
{
double tp1 = (initial.getCloseAt(i) + initial.getHighAt(i) + initial.getLowAt(i)) / 3;
double tp2 = (initial.getCloseAt(i-1) + initial.getHighAt(i-1) + initial.getLowAt(i-1)) / 3;
double rmf = tp1 * initial.getVolumeAt(i);
if (tp1 > tp2)
posMF.setDataItem(i, new DataItem(initial.getTimeAt(i), rmf));
else
negMF.setDataItem(i, new DataItem(initial.getTimeAt(i), rmf));
}
Dataset d = Dataset.EMPTY(count);
for (int i = period; i < count; i++)
{
double posSum = 0;
double negSum = 0;
for (int j = 0; j < period; j++)
{
posSum += posMF.getDataItem(i-j) != null ? posMF.getCloseAt(i-j) : 0;
negSum += negMF.getDataItem(i-j) != null ? negMF.getCloseAt(i-j) : 0;
}
double mr = posSum / negSum;
double mfi = 100 - (100 / (1 + mr));
d.setDataItem(i, new DataItem(initial.getTimeAt(i), mfi));
}
return d;
}
}